package com.mingke.java.NewIO;

import com.mingke.java.NIO.NIOSocketHandler;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * @author mingke
 * @function 进行代码重构之前的的NIO程序，优化后的代码详见NIO包
 * @date 2021/11/9
 */
public class NewIOServer {
    public static void main(String[] args) throws IOException {
        //用于处理请求的线程池
        final ThreadPoolExecutor threadPool = new ThreadPoolExecutor(20, 1000, 30, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(1000));

        //开启一个服务端的通道
        ServerSocketChannel serverSocketChannel = null;
        serverSocketChannel = ServerSocketChannel.open();
        //设置服务器的端口号
        InetSocketAddress inetSocketAddress = new InetSocketAddress(2021);
        serverSocketChannel.bind(inetSocketAddress);
        //设置服务端为非阻塞的形式监听通道
        serverSocketChannel.configureBlocking(false);
        //设置一个selector
        Selector selector = Selector.open();
        //设置此时通道管制的信息为连接请求
        serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
        System.out.println("服务器已启动");
        //轮训
        while(true) {
            //此处的select是阻塞的，只有有信息了，才会往下走
            int flag = selector.select();
            if(flag == 0) {
                continue;
            }
            //获取到的连接上的keys
            Set<SelectionKey> keys = selector.selectedKeys();
            //获取到迭代器，并且开始遍历
            Iterator<SelectionKey> iterator = keys.iterator();
            while(iterator.hasNext()) {
                //获取到当前的key
                SelectionKey key = iterator.next();
                //移除掉已经用到的key，避免重复判断
                iterator.remove();
                if(key.isAcceptable()) {  //连接响应
                    //这个类似于之前的那个accept，会进行阻塞
                    //之前的的时阻塞到有连接，现在是有连接才阻塞，所以阻塞也会立刻解除，得到客户端连接的Channel
                    SocketChannel socketChannel = serverSocketChannel.accept();
                    //设置客户端连接为非阻塞
                    socketChannel.configureBlocking(false);
                    //这册当前selector关心的内容，需要设置相关缓冲区大侠，不然会打印失败
                    socketChannel.register(key.selector(), SelectionKey.OP_READ, ByteBuffer.allocate(512));
                    System.out.println("一个新连接");
                }
                if(key.isReadable()) {   //收到消息响应
                    SocketChannel clientSocketChannel = (SocketChannel)key.channel();
                    //System.out.println("socket readable");
                    if(!clientSocketChannel.isConnected()) {
                        clientSocketChannel.finishConnect();
                        key.cancel();
                        clientSocketChannel.close();
                        System.out.println("socket closed2");
                        continue;
                    }
                    ByteBuffer buffer = (ByteBuffer)key.attachment();
                    int len = clientSocketChannel.read(buffer);

                    if(len == -1) {
                        clientSocketChannel.finishConnect();
                        key.cancel();
                        clientSocketChannel.close();
                        System.out.println("socket closed1");
                    } else {
                        buffer.flip();
                        int bufferLength = buffer.limit();
                        byte bytes[] = new byte[bufferLength];
                        buffer.get(bytes, 0, bufferLength);
                        System.out.println("数据长度为："+bufferLength+" 数据内容如下");
                        for(int i = 0; i < bufferLength; i++) {
                            if(i == bufferLength-1) {
                                System.out.print(bytes[i] + "\n");
                            }else {
                                System.out.print(bytes[i] + " ");
                            }
                        }
                        buffer.clear();
                    }
                }
            }
        }
    }
}
